package me.spring.cloud.common.components.oss.cloud.aliyun;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.PutObjectResult;
import me.spring.cloud.common.components.oss.cloud.AbstractCloudStoreServiceImpl;
import me.spring.cloud.common.components.util.constant.CharConstant;
import me.spring.cloud.common.components.util.io.FileHelper;
import me.spring.cloud.common.components.util.lang.StringUtil;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;

/**
 * 阿里云存储
 * @author huangzhibin
 * @date 2018-07-26 16:22
 */
@Slf4j
public class AliyunCloudStorageServiceImpl extends AbstractCloudStoreServiceImpl {

  private OSSClient client;

  public AliyunCloudStorageServiceImpl(@NotNull AliyunCloudConfig config) {
    super.setConfig(config);
    client = new OSSClient(config.getAliyunEndPoint(), new DefaultCredentialProvider(config.getAliyunAccessKeyId(),
        config.getAliyunAccessKeySecret()), new ClientConfiguration());
  }

  /**
   * @param fileName 文件名称（可以有路径）
   * @Return java.lang.String
   * @Author luffy
   * @Description 拼接阿里云文件访问url
   * @Date 2019-07-05 15:44
   */
  private String getUrl(@NotNull String fileName) throws Exception {
    if (this.getConfig().getDomain().endsWith(String.valueOf(CharConstant.SLASH))) {
      if (fileName.startsWith(String.valueOf(CharConstant.SLASH))) {
        return StringUtil.append(this.getConfig().getDomain(), fileName.substring(1, fileName.length() - 1));
      } else {
        return StringUtil.append(this.getConfig().getDomain(), fileName);
      }
    }
    if (fileName.startsWith(String.valueOf(CharConstant.SLASH))) {
      return StringUtil.append(this.getConfig().getDomain(), fileName);
    } else {
      return StringUtil.append(this.getConfig().getDomain(), String.valueOf(CharConstant.SLASH), fileName);
    }
  }

  /**
   * @param file 文件(绝对路径)
   * @param fileName （文件名称 不能为null）
   * @Return com.aliyun.oss.model.PutObjectResult
   * @author luffy
   * @Description 上传本地文件
   * @date 2019-07-05
   */
  private PutObjectResult uploadLocal(String file, @NotNull String fileName) throws Exception {
    return client.putObject(super.getConfig().getBucketName(), fileName, new File(file));
  }

  /**
   * @param data 文件字节
   * @param fileName （文件名称 不能为null）
   * @Return com.aliyun.oss.model.PutObjectResult
   * @Author luffy
   * @Description 上传byte文件
   * @Date 2019-07-05 15:28
   */
  private PutObjectResult uploadByte(byte[] data, String fileName) throws Exception {
    return client.putObject(super.getConfig().getBucketName(), fileName, new ByteArrayInputStream(data));
  }

  /**
   * @param inputStream 文件流
   * @param fileName （文件名称 不能为null）
   * @Return com.aliyun.oss.model.PutObjectResult
   * @Author luffy
   * @Description 上传流文件
   * @Date 2019-07-05 15:33
   */
  private PutObjectResult uploadInputStream(@NotNull InputStream inputStream, @NotNull String fileName)
      throws Exception {
    return client.putObject(super.getConfig().getBucketName(), fileName, inputStream);
  }

  /**
   * @param remoteSrcUrl 网络文件地址
   * @Return com.aliyun.oss.model.PutObjectResult
   * @Author luffy
   * @Description 上传网络文件
   * @Date 2019-07-05 15:41
   */
  private PutObjectResult uploadRemoteSrcUrl(@NotNull String remoteSrcUrl, @NotNull String fileName) throws Exception {
    return client.putObject(super.getConfig().getBucketName(), fileName, new URL(remoteSrcUrl).openStream());
  }

  /**
   * @param file 文件(绝对路径)
   * @param fileName （文件名称 未null时会自动生成）
   * @Return java.lang.String
   * @Description 上传本地文件
   * @author luffy
   * @date 2019-07-05
   */
  @Override
  public String uploadForLocal(@NotNull String file, String fileName) throws Exception {
    if (StringUtil.isEmpty(fileName)) {
      fileName = FileHelper.getName(file);
    }
    this.uploadLocal(file, fileName);
    return this.getUrl(fileName);
  }

  /**
   * @param data 文件字节
   * @param fileName （文件名称 未null时会自动生成）
   * @param mime 指定文件mimetype
   * @Return java.lang.String
   * @Author luffy
   * @Description 上传byte文件
   * @Date 2019-07-05 15:28
   */
  @Override
  public String uploadForByte(@NotNull byte[] data, String fileName, @NotNull String mime) throws Exception {
    fileName = this.constructFileName(fileName, mime);
    this.uploadByte(data, fileName);
    return this.getUrl(fileName);
  }

  /**
   * @param inputStream 文件流
   * @param fileName （文件名称 未null时会自动生成）
   * @param mime 指定文件mimetype
   * @Return java.lang.String
   * @Author luffy
   * @Description 上传流文件
   * @Date 2019-07-05 15:33
   */
  @Override
  public String uploadForInputStream(@NotNull InputStream inputStream, String fileName, @NotNull String mime)
      throws Exception {
    fileName = this.constructFileName(fileName, mime);
    this.uploadInputStream(inputStream, fileName);
    return this.getUrl(fileName);
  }

  /**
   * @param remoteSrcUrl 网络文件地址
   * @Return java.lang.String
   * @Author luffy
   * @Description 上传网络文件
   * @Date 2019-07-05 15:42
   */
  @Override
  public String uploadForRemoteSrcUrl(String remoteSrcUrl, String fileName) throws Exception {
    if (StringUtil.isEmpty(fileName)) {
      fileName = FileHelper.parseSuffix(remoteSrcUrl);
    }
    this.uploadRemoteSrcUrl(remoteSrcUrl, fileName);
    return this.getUrl(fileName);
  }

  /**
   * @param fileName 文件名称
   * @param newMimeType 文件类型
   * @Return void
   * @Author luffy
   * @Description 修改文件类型
   * @Date 2019-07-05 15:45
   */
  @Override
  public void modifyMimeType(@NotNull String fileName, @NotNull String newMimeType) throws Exception {
  }

  /**
   * @param fileMimeMap 文件名称:文件类型
   * @Return java.util.HashMap<java.lang.String, java.util.Map < java.lang.String, java.lang.Object>>
   * @Author luffy
   * @Description 批量修改文件类型
   * @Date 2019-07-05 15:46
   */
  public HashMap<String, Map<String, Object>> batchModifyMimeType(@NotNull HashMap<String, String> fileMimeMap)
      throws Exception {
    return null;
  }

  private Map<String, Object> createMap() {
    Map<String, Object> keyMap = new HashMap<>(2);
    keyMap.put("isOk", false);
    return keyMap;
  }

  /**
   * @param fileNames 文件名称
   * @Return java.util.HashMap<java.lang.String, java.util.Map < java.lang.String, java.lang.Object>>
   * @Author luffy
   * @Description 批量删除文件
   * @Date 2019-07-05 15:46
   */
  @Override
  public HashMap<String, Map<String, Object>> batchDelete(@NotNull String... fileNames) throws Exception {
    DeleteObjectsResult deleteObjectsResult = client.deleteObjects(
        new DeleteObjectsRequest(super.getConfig().getBucketName()).withKeys(Arrays.asList(fileNames)));
    List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
    HashMap<String, Map<String, Object>> retMap = new HashMap<>(fileNames.length);
    deletedObjects.forEach(s -> retMap.put(s, this.createMap()));
    return retMap;
  }

  /**
   * @param fileName 文件名称
   * @param newFileName 新文件名称
   * @Return java.lang.String
   * @Author luffy
   * @Description 重命名
   * @Date 2019-07-05 15:47
   */
  @Override
  public String renameFile(@NotNull String fileName, @NotNull String newFileName) throws Exception {
    return null;
  }

  /**
   * @param fileName 文件名称
   * @param newFileName 新文件名称
   * @Return java.lang.String
   * @Author luffy
   * @Description 强制复制文件
   * @Date 2019-07-05 15:49
   */
  public String copyFile(@NotNull String fileName, @NotNull String newFileName) throws Exception {
    return null;
  }

  /**
   * @param fileName 文件名称
   * @Return void
   * @Author luffy
   * @Description 删除文件
   * @Date 2019-07-05 15:49
   */
  @Override
  public void delete(@NotNull String fileName) throws Exception {
    client.deleteObject(super.getConfig().getBucketName(), fileName);
  }

  /**
   * @Author luffy
   * @Description 判断手否存在文件
   * @Param file
   * @Return boolean
   * @Date 2019-09-18 16:40
   */
  @Override
  public boolean isExists(@NotNull String file) throws Exception {
    return client.doesObjectExist(super.getConfig().getBucketName(), file);
  }
}
